package com.example.demo.controller;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONReader;
import com.dhcc.csmsearch.elasticsearch.common.ElasticsearchManage;
import com.example.demo.core.entity.BulkResponseBody;
import com.example.demo.core.entity.RestResult;
import com.example.demo.core.entity.ESBulkModel;
import com.example.demo.core.enums.ElasticTypeEnum;
import com.example.demo.core.utils.ResultUtil;
import com.example.demo.jobs.ConvertPipeline;
import com.example.demo.jobs.analysis.CaseBulkMode;
import com.example.demo.jobs.analysis.CaseRecodrXmlBean;
import com.example.demo.jobs.analysis.CaseRecordXmlAnaly;
import com.example.demo.jobs.analysis.XmlFileBulkReader;
import com.example.demo.jobs.hbase.HBaseBulkProcessor;
import com.example.demo.jobs.hbase.LibAHBaseSyn;
import com.example.demo.mock.MockUtil;
import com.example.demo.service.DefaultDicMapService;
import com.example.demo.service.ElasticBulkService;
import com.huawei.fusioninsight.elasticsearch.transport.client.PreBuiltHWTransportClient;
import org.apache.commons.collections.map.HashedMap;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.io.SAXReader;
import org.elasticsearch.action.bulk.BulkRequestBuilder;
import org.elasticsearch.action.bulk.BulkResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.ResourceUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import springfox.documentation.spring.web.json.Json;

import javax.annotation.Resource;
import java.io.File;
import java.io.StringReader;
import java.nio.charset.StandardCharsets;
import java.util.*;

@RestController
@RequestMapping("/test")
public class DemoTestController {
    private int TOTAL = 10000;
    private boolean isDev = false;
    private static Base64.Encoder encoder = Base64.getEncoder();
    private static Base64.Decoder decoder = Base64.getDecoder();
    private final static String ENV_DEV = "dev";

    @Autowired
    private DefaultDicMapService defaultDicMapService;

    @Autowired
    private ElasticBulkService elasticBulkService;

    @Resource
    private ElasticsearchManage elasticsearchManage;

    @Resource(name = "env")
    private String curEnv;

    @GetMapping("bulk/patient")
    public RestResult bulkPatient() throws Exception {
        MockUtil mock = new MockUtil(curEnv, TOTAL);
        List<Map<String, Object>> maps = mock.buildPatientData();
        List<Object> reList = exeConvert(maps, ElasticTypeEnum.PATIENT);
        if (curEnv.equals(ENV_DEV)) {
            exeBulk(maps, ElasticTypeEnum.PATIENT);
        }

        return ResultUtil.success(reList);
    }

    @GetMapping("bulk/patient/1")
    public RestResult bulkPatientTest() throws Exception {
        List<Map<String, Object>> maps = new ArrayList<>();
        Map<String, Object> map1 = new HashedMap();
        map1.put("id", "08419303");
        map1.put("routing", "08419303");
        map1.put("pat_regno", "08419303");
        map1.put("pat_recordno", "");
        map1.put("pat_name", "谢雨航");
        map1.put("pat_idcard", "141122199309090101");
        map1.put("pat_birthday", "2005-07-08");
        maps.add(map1);
        List<Object> reList = exeConvert(maps, ElasticTypeEnum.PATIENT);
        if (curEnv.equals(ENV_DEV)) {
            exeBulk(maps, ElasticTypeEnum.PATIENT);
        }

        return ResultUtil.success(reList);
    }

    @GetMapping("convert/patient")
    public RestResult convertPatient() throws Exception {
        MockUtil mock = new MockUtil(curEnv, TOTAL);
        List<Map<String, Object>> maps = mock.buildPatientData();
        List<Object> reList = exeConvert(maps, ElasticTypeEnum.PATIENT);
        return ResultUtil.success(reList);
    }

    @GetMapping("convert/medicalrecord")
    public RestResult convertAdm() throws Exception {
        MockUtil mock = new MockUtil(curEnv, TOTAL);
        List<Map<String, Object>> maps = mock.buildAdmData();
        List<Object> reList = exeConvert(maps, ElasticTypeEnum.MEDICAL_RECORD);
        return ResultUtil.success(reList);
    }

    @GetMapping("bulk/medicalrecord")
    public RestResult bulkAdm() throws Exception {
        MockUtil mock = new MockUtil(curEnv, TOTAL);
        List<Map<String, Object>> maps = mock.buildAdmData();
        List<Object> reList = exeConvert(maps, ElasticTypeEnum.MEDICAL_RECORD);
        if (curEnv.equals(ENV_DEV)) {
            exeBulk(maps, ElasticTypeEnum.MEDICAL_RECORD);
        }
        return ResultUtil.success(reList);
    }

    @GetMapping("bulk/medicalrecord/1")
    public RestResult bulkAdmTest() throws Exception {
        List<Map<String, Object>> maps = new ArrayList<>();
        Map<String, Object> map1 = new HashedMap();
        map1.put("mr_admid", "9490476");
        map1.put("mr_regno", "03631757");

        map1.put("mr_admdate", "2014-05-09 13:18:55");
        map1.put("mr_admtime", "13:18:55");
        map1.put("mr_dischdate", "");
        map1.put("mr_dischtime", "");
        maps.add(map1);
        List<Object> reList = exeConvert(maps, ElasticTypeEnum.MEDICAL_RECORD);
        if (curEnv.equals(ENV_DEV)) {
            exeBulk(maps, ElasticTypeEnum.MEDICAL_RECORD);
        }

        return ResultUtil.success(reList);
    }

    /**
     * 数据转换测试
     *
     * @return
     */
    @GetMapping("convert/diagnose")
    public RestResult convertDiagnose() throws Exception {
        MockUtil mock = new MockUtil(curEnv, TOTAL);
        List<Map<String, Object>> maps = mock.buildDiagnoseData();
        List<Object> reList = exeConvert(maps, ElasticTypeEnum.DIAGNOSE);
        return ResultUtil.success(reList);
    }

    @GetMapping("bulk/diagnose")
    public RestResult bulkDiagnose() throws Exception {
        MockUtil mock = new MockUtil(curEnv, TOTAL);
        List<Map<String, Object>> maps = mock.buildDiagnoseData();
        List<Object> reList = exeConvert(maps, ElasticTypeEnum.DIAGNOSE);
        if (curEnv.equals(ENV_DEV)) {
            exeBulk(maps, ElasticTypeEnum.DIAGNOSE);
        }

        return ResultUtil.success(reList);
    }

    @GetMapping("bulk/diagnose/1")
    public RestResult bulkDiagnoseTest() throws Exception {
        List<Map<String, Object>> maps = new ArrayList<>();
        Map<String, Object> map1 = new HashedMap();
        map1.put("diag_id", "20366318||1");
        map1.put("diag_admid", "20366318");
        map1.put("diag_regno", "09100140");
        map1.put("diag_date", "2018-05-18 00:00:00");
        map1.put("diag_time", "10:33:01");
        map1.put("diag_code", "15369");
        maps.add(map1);
        List<Object> reList = exeConvert(maps, ElasticTypeEnum.DIAGNOSE);
        if (curEnv.equals(ENV_DEV)) {
            exeBulk(maps, ElasticTypeEnum.DIAGNOSE);
        }

        return ResultUtil.success(reList);
    }

    @GetMapping("convert/orditem")
    public RestResult convertOrdItem() throws Exception {
        MockUtil mock = new MockUtil(curEnv, TOTAL);
        List<Map<String, Object>> maps = mock.buildOrdItemData();
        List<Object> reList = exeConvert(maps, ElasticTypeEnum.ORDITEM);

        return ResultUtil.success(reList);
    }

    @GetMapping("convert/suggestion")
    public RestResult suggestion() {
        BulkResponseBody result = elasticBulkService.bulkSuggestion();
        return ResultUtil.success(result);
    }

    @GetMapping("bulk/orditem")
    public RestResult bulkOrdItem() throws Exception {
        MockUtil mock = new MockUtil(curEnv, TOTAL);
        List<Map<String, Object>> maps = mock.buildOrdItemData();
        List<Object> reList = exeConvert(maps, ElasticTypeEnum.ORDITEM);

        BulkResponseBody responseBody = exeBulk(maps, ElasticTypeEnum.ORDITEM);
        return ResultUtil.success(responseBody);
    }

    @GetMapping("bulk/orditem/1")
    public RestResult bulkOrdItemTest() throws Exception {
        List<Map<String, Object>> maps = new ArrayList<>();
        Map<String, Object> map1 = new HashedMap();
        map1.put("ord_id", "241167||56");
        map1.put("ord_admno", "243384");
        map1.put("ord_regno", "00173380");
        map1.put("ord_startdate", "2009-09-17 00:00:00");
        map1.put("ord_starttime", "17:35:00");
        map1.put("ord_enddate", "");
        map1.put("ord_endtime", "");
        map1.put("ord_doseqty", "1");
        map1.put("ord_code", "120400002");

        maps.add(map1);
        List<Object> reList = exeConvert(maps, ElasticTypeEnum.ORDITEM);
        BulkResponseBody responseBody = null;
        if (curEnv.equals(ENV_DEV)) {
             responseBody = exeBulk(maps, ElasticTypeEnum.ORDITEM);
        }

        return ResultUtil.success(responseBody);
    }

    @GetMapping("convert/lisitem")
    public RestResult convertLisItem() throws Exception {
        MockUtil mock = new MockUtil(curEnv, TOTAL);
        List<Map<String, Object>> maps = mock.buildLisitemData();
        List<Object> reList = exeConvert(maps, ElasticTypeEnum.Lisitem);
        return ResultUtil.success(reList);
    }

    @GetMapping("bulk/lisitem")
    public RestResult bulkLisItem() throws Exception {
        MockUtil mock = new MockUtil(curEnv, TOTAL);
        List<Map<String, Object>> maps = mock.buildLisitemData();
        List<Object> reList = exeConvert(maps, ElasticTypeEnum.Lisitem);
        if (curEnv.equals(ENV_DEV)) {
            exeBulk(maps, ElasticTypeEnum.Lisitem);
        }

        return ResultUtil.success(reList);
    }

    @GetMapping("convert/ordris")
    public RestResult convertOrdRis() throws Exception {
        MockUtil mock = new MockUtil(curEnv, TOTAL);
        List<Map<String, Object>> maps = mock.buildOrdRisData();
        List<Object> reList = exeConvert(maps, ElasticTypeEnum.OrdRis);
        return ResultUtil.success(reList);
    }

    @GetMapping("bulk/ordris")
    public RestResult bulkOrdRis() throws Exception {
        MockUtil mock = new MockUtil(curEnv, TOTAL);
        List<Map<String, Object>> maps = mock.buildOrdRisData();
        List<Object> reList = exeConvert(maps, ElasticTypeEnum.OrdRis);
        if (curEnv.equals(ENV_DEV)) {
            exeBulk(maps, ElasticTypeEnum.OrdRis);
        }

        return ResultUtil.success(reList);
    }

    @PostMapping(path = "convert/casetest/{theme}/{filename}/{num}")
    public RestResult bulkCaseText(@PathVariable(name = "theme") String theme,
                                   @PathVariable(name = "num") String num,
                                   @PathVariable(name = "filename") String filename) {

//        long startTime = System.currentTimeMillis();
//        BulkResponseBody responseBody = elasticBulkService.bulkCase(body, false);
//        long endTime = System.currentTimeMillis();
//
//        System.out.println("=====bulk [ " + body.get(0).getDocumentTypeDesc() + " ],tool：" + (endTime - startTime) + "ms，message:" + responseBody.getResultContent());
//
//        return ResultUtil.success(responseBody);
        return null;
    }

    @GetMapping("convert/case/{fileName}")
    public RestResult convertCaseRecord(@PathVariable String fileName,
                                        @RequestParam(value = "num", defaultValue = "1", required = false) int num) throws Exception {
        // 创建SAXReader的对象reader
        SAXReader reader = new SAXReader();
        String curfileName = "ryjl-all.xml";
        ElasticTypeEnum typeEnum = ElasticTypeEnum.Residentadmitnote;
        switch (fileName) {
            case "ryjl":
            case "ryjl.xml":
                curfileName = "ryjl-all.xml";
                typeEnum = ElasticTypeEnum.Residentadmitnote;
                break;
            case "ryjl1":
            case "ryjl1.xml":
                curfileName = "ryjl1.xml";
                typeEnum = ElasticTypeEnum.Residentadmitnote;
                break;
            case "basy":
            case "basy.xml":
            case "basy1":
                curfileName = "bnsy1.xml";
                typeEnum = ElasticTypeEnum.MedicalRecordHomePage;
                break;
            case "basy2":
            case "basy2.xml":
                curfileName = "bnsy2.xml";
                typeEnum = ElasticTypeEnum.MedicalRecordHomePage;
                break;
            default:
                break;

        }
        File file = new File(System.getProperty("user.dir") + "/" + curfileName);
        if (!file.exists()) {
            file = new File(ResourceUtils.getURL("classpath:" + fileName).getPath());
        }

        Document document = reader.read(file);

        // 编码解码测试
        String parseText = document.asXML();
        String xmlStrBase64 = new String(encoder.encode(parseText.getBytes()), StandardCharsets.UTF_8);

        long decoderTime = System.currentTimeMillis();

        for (int i = 0; i < num; i++) {
            //base64解码
            String xmlStr = new String(decoder.decode(xmlStrBase64), StandardCharsets.UTF_8);

            if (!StringUtils.isEmpty(xmlStr)) {
                // xmlStr 转 Document
                Document document1 = DocumentHelper.parseText(xmlStr);
            }
        }

        long decoderEndTime = System.currentTimeMillis();
        System.out.println("Decode batch: " + num + ", time: " + (decoderEndTime - decoderTime) + "ms");

        long startTime = System.currentTimeMillis();
        CaseRecodrXmlBean bean = null;
        for (int i = 0; i < num; i++) {
            bean = CaseRecordXmlAnaly.analyCaseRecordXml(document, typeEnum);
        }
        long endTime = System.currentTimeMillis();
        System.out.println("AnalyXml batch: " + num + ", time: " + (endTime - startTime) + "ms");
        Map<String, Object> maps = bean.getAnalyResult();
        maps.put("documentid", "111112");
        maps.put("visitnumber", "9490476t");
        maps.put("patientid", "03631757t");
        ESBulkModel bulkMode = null;
        for (int i = 0; i < num; i++) {
            bulkMode = ConvertPipeline
                    .convertToBulkModel(typeEnum, maps, true);
        }

        long endTime1 = System.currentTimeMillis();
        System.out.println("ConvertXml batch: " + num + ", time: " + (endTime1 - endTime) + "ms");
        return ResultUtil.success(bulkMode);
    }

    @GetMapping("bulk/case/{fileName}")
    public RestResult bulkCaseRecord(@PathVariable String fileName) throws Exception {
        // 创建SAXReader的对象reader
        SAXReader reader = new SAXReader();
        String curfileName = "ryjl-all.xml";
        ElasticTypeEnum typeEnum = ElasticTypeEnum.Residentadmitnote;
        switch (fileName) {
            case "ryjl":
            case "ryjl.xml":
                curfileName = "ryjl-all.xml";
                typeEnum = ElasticTypeEnum.Residentadmitnote;
                break;
            case "basy":
            case "basy.xml":
            case "basy1":
                curfileName = "bnsy1.xml";
                typeEnum = ElasticTypeEnum.MedicalRecordHomePage;
                break;
            case "basy2":
            case "basy2.xml":
                curfileName = "bnsy2.xml";
                typeEnum = ElasticTypeEnum.MedicalRecordHomePage;
                break;
            default:
                break;
        }
        File file = new File(System.getProperty("user.dir") + File.separator + curfileName);
        if (!file.exists()) {
            file = new File(ResourceUtils.getURL("classpath:" + fileName).getPath());
        }
        XmlFileBulkReader xmlReader = XmlFileBulkReader.getInstance();
        long startTime = System.currentTimeMillis();
        for (int i = 0; i < 1; i++) {
            Document document = reader.read(file);
//            maps.put("documentid", "11111");
//            maps.put("visitnumber", "9490476t");
//            maps.put("patientid", "03631757t");
            CaseBulkMode bulkMode = new CaseBulkMode("csmsearch",
                    typeEnum.getEsType(),
                    "12345" + i,
                    "9490474",
                    "03631757",
                    document, typeEnum);
            xmlReader.add(bulkMode);
        }
        long endTime = System.currentTimeMillis();

        return ResultUtil.success("成功，time tool: " + (endTime - startTime));
    }

    //hbase测试
    @GetMapping("hbasetest")
    public RestResult hbaseTest() throws Exception {
        long start = System.currentTimeMillis();
        try {
            LibAHBaseSyn libAHBaseSyn = LibAHBaseSyn.getInstance();
            libAHBaseSyn.setParams("2019-07-01", "2019-07-11");
            long size = 0;
            for (int m = 0; m < 1; m++) {
//                long batch = libAHBaseSyn.testQuery(ElasticTypeEnum.MEDICAL_RECORD.getEsType());
//                size = size + batch;
                MockUtil mock = new MockUtil(curEnv, TOTAL);
                List<Map<String, Object>> maps = mock.buildAdmData();
                //ElasticTypeEnum typeEnum = ElasticTypeEnum.getByEsType();
//                List<ESBulkModel> models = ConvertPipeline.convertToBulkModels(ElasticTypeEnum.MEDICAL_RECORD, maps,
//                        true);
//
//                for (ESBulkModel model : models){
//                    hBaseBulkProcessor.add(model);
//                }

                size += maps.size();
            }
            long end = System.currentTimeMillis();
            Map<String, Object> map = new HashMap<>();
            map.put("time", (end - start) + "ms");
            map.put("model", "成功导入" + size + "条");
            return ResultUtil.success(map);
        } catch (Exception e) {
            return ResultUtil.error(e.getMessage());
        }

    }

    @GetMapping("hbase/{table}/{startdate}/{enddate}")
    public RestResult hbase(@PathVariable(name = "table") String table,
                            @PathVariable(name = "startdate") String startdate,
                            @PathVariable(name = "enddate") String enddate) throws Exception {
        long start = System.currentTimeMillis();
        try {
            ElasticTypeEnum typeEnum = ElasticTypeEnum.getByEsType(table);
            if (typeEnum == null) {
                return ResultUtil.error("table 的名称不再指定范围内,name:{}", table);
            }
            LibAHBaseSyn libAHBaseSyn = LibAHBaseSyn.getInstance();
            libAHBaseSyn.setParams(startdate, enddate);
            long size = libAHBaseSyn.testQuery(typeEnum.getEsType());

            long end = System.currentTimeMillis();
            Map<String, Object> map = new HashMap<>();
            map.put("time", (end - start) + "ms");
            map.put("model", "成功导入" + size + "条");
            System.out.println(JSON.toJSONString(map));
            return ResultUtil.success(map);
        } catch (Exception e) {
            return ResultUtil.error(e.getMessage());
        }

    }

    @GetMapping("elastic/updatetest")
    public RestResult testEsUpdate(){
        PreBuiltHWTransportClient client = elasticsearchManage.getTransportClient();
        Map<String, Object> map = new HashMap<>();
//        map.put("name", "testName");
//        map.put("age", 11);
        map.put("sex", "男");
        map.put("address", "bb");
        map.put("phone", "11111");
//        map.put("nation", "test");
        BulkRequestBuilder bulkRequest = client.prepareBulk();
        bulkRequest.add(client.prepare().prepareUpdate("test", "doc", "test11")
                .setDoc(map).setDetectNoop(true).setDocAsUpsert(true)
        );
        BulkResponse bulkResponse = bulkRequest.get();
        if (bulkResponse.hasFailures()) {
            return ResultUtil.error(bulkResponse.buildFailureMessage());
            // process failures by iterating through each bulk response item
        }
        return ResultUtil.success();
    }


    private List<Map<String, Object>> strToMap(String dataJsonStr) {
        long startTime = System.currentTimeMillis();   //获取开始时间
        JSONReader reader = new JSONReader(new StringReader(dataJsonStr));//已流的方式处理，这里很快
        reader.startArray();
        List<Map<String, Object>> rsList = new ArrayList<Map<String, Object>>();
        Map<String, Object> map = null;
        int i = 0;
        while (reader.hasNext()) {
            i++;
            reader.startObject();//这边反序列化也是极速
            map = new HashMap<String, Object>();
            while (reader.hasNext()) {
                String arrayListItemKey = reader.readString();
                String arrayListItemValue = reader.readObject().toString();
                map.put(arrayListItemKey, arrayListItemValue);
            }
            rsList.add(map);
            reader.endObject();
        }
        reader.endArray();
        long endTime = System.currentTimeMillis(); //获取结束时间
        System.out.println("strToMap耗时：" + (endTime - startTime) + "ms");

        return rsList;
    }

    private List<Map<String, Object>> strToMapBy(String dataJsonStr) {
        long startTime = System.currentTimeMillis();   //获取开始时间

        List<Map<String, Object>> listObjectFir = JSONArray.parseObject(dataJsonStr, List.class);
        long endTime = System.currentTimeMillis(); //获取结束时间
        System.out.println("strToMap JSON 耗时：" + (endTime - startTime) + "ms");

        return listObjectFir;
    }

    private List<Object> exeConvert(List<Map<String, Object>> maps, ElasticTypeEnum typeEnum) throws Exception {

        List<Object> reList = new ArrayList<>();
        long startTime = System.currentTimeMillis();   //获取开始时间
        List<ESBulkModel> bulkModels = defaultDicMapService.test(maps, typeEnum);

        if (bulkModels.size() > 10) {
            reList.addAll(bulkModels.subList(0, 10));
        } else {
            reList.addAll(bulkModels.subList(0, bulkModels.size()));
        }
        // 导入医嘱的
        if (typeEnum.equals(ElasticTypeEnum.ORDITEM)) {
            int i = 0;
            int j = 0;
            // 转换药物
            // 转换用药
            for (ESBulkModel bulkModel : bulkModels) {
                ESBulkModel otherModel = ConvertPipeline.convertToBulkModel(ElasticTypeEnum.Medicine,
                        bulkModel.getMapData(), true);
                if (i < 5 && otherModel != null) {
                    reList.add(otherModel);
                }
                i++;
            }
            for (ESBulkModel bulkModel : bulkModels) {
                ESBulkModel otherModel = ConvertPipeline.convertToBulkModel(ElasticTypeEnum.OrdLis,
                        bulkModel.getMapData(), true);
                if (j < 5 && otherModel != null) {
                    reList.add(otherModel);
                }
                j++;
            }
        }

        long endTime = System.currentTimeMillis(); //获取结束时间
        Map<String, String> m = new HashMap<>();
        m.put("totla", "共有" + bulkModels.size() + "条");
        m.put("exeTime", "执行时间：" + (endTime - startTime) + "ms");
        reList.add(m);

        return reList;
    }

    private BulkResponseBody exeBulk(List<Map<String, Object>> reList, ElasticTypeEnum typeEnum) {
        long startTime = System.currentTimeMillis();   //获取开始时间
        String dataStr = JSON.toJSONString(reList);
        String theme = typeEnum.getTheme();
        BulkResponseBody responseBody = elasticBulkService.bulk(theme, dataStr);
        long endTime = System.currentTimeMillis(); //获取结束时间

        System.out.println("bulk convert esModel time：" + (endTime - startTime) + "ms");
        return responseBody;
    }

}
